/**
 * this永远指向最后调用它的那个对象
 */

/**
 * 怎么改变this的指向？
 */
// 1. 使用es6的箭头函数
// 2. 在函数内部使用_this = this
// 3. 使用apply，call，bind
// 4. new 实例化一个对象


/**
 * 箭头函数
 */
/* 
箭头函数的this始终指向函数定义时的this，而非执行时。箭头函数中没有this绑定，必须通过
查找作用域链来决定其值，如果箭头函数被非箭头函数包含，则this绑定的是最近一层函数的this
否则this为undefined
*/
var name = 'windowName'
var a = {
    name:'Cherry',
    fun1:function() {
        console.log(this.name);
    },
    fun2:function() {
        setTimeout(() => {
            this.fun1() 
        }, 100)
    }
}
a.fun2() // Cherry


/**
 * 在函数内部使用_this = this
 */
/*
将调用这个函数的对象保存在变量 _this 中，然后在函数中都使用这个 _this，这样 _this 就不会改变了。
*/
var name = "windowsName";
var a = {
    name : "Cherry",
    func1: function () {
        console.log(this.name)     
    },
    func2: function () {
        var _this = this;
        setTimeout( function() {
            _this.func1()
        },100);
    }
};
a.func2()       // Cherry


/**
 * 使用apply，bind，call
 * apply() 方法调用一个函数, 其具有一个指定的this值，以及作为一个数组（或类似数组的对象）提供的参数
 * bind()方法创建一个新的函数, 当被调用时，将其this关键字设置为提供的值，在调用新函数时，在任何提供之前提供一个给定的参数序列。
 * call() 方法调用一个函数, 其具有一个指定的this值，以及作为一个参数列表(多个参数)提供的参数
 */

/*
eg：
var name = 'windowName'
function a() {
    let name = '123'
    function b() {
        console.log(this.name);
    }
    b()
}
a()
*/

/**
 * 使用new
 * 1. 创建一个空对象 obj
 * 2. 将新创建的空对象的隐式原型指向其构造函数的显示原型
 * 3. 使用call改变this的指向
 * 4. 如果无返回值或者返回一个对象值，则将obj返回作为新对象，如果返回一个新对象的话那么直接返回该对象 
 **/ 
function my(fn, ...arguments) {
    let newObj = {}
    newObj = Object.create(fn.prototype)
    let result = fn.call(newObj, arguments)
    return typeof result == 'object' ? result : newObj
}




/**
 *作为函数方法调用函数 
 **/ 
/*
在 JavaScript 中, 函数是对象。JavaScript 函数有它的属性和方法。call() 和 apply() 是预定义的函数方法。 
两个方法可用于调用函数，两个方法的第一个参数必须是对象本身在 JavaScript 严格模式(strict mode)下, 
在调用函数时第一个参数会成为 this 的值， 即使该参数不是一个对象。在 JavaScript 非严格模式(non-strict mode)下, 
如果第一个参数的值是 null 或 undefined, 它将使用全局对象替代。
*/